home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / vim_src.zip / SCRIPT.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  9KB  |  429 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMitation
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * script.c: functions for handling script files
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "proto.h"
  18. #include "param.h"
  19.  
  20. static char *scriptname;            /* name of the script in use */
  21. static FILE *autoscriptfd = NULL;
  22. static char *makescriptname __ARGS((void));
  23. static void Supdatescript __ARGS((char *));
  24.  
  25. extern int global_busy;            /* this is in csearch.c */
  26.  
  27. /*
  28.  * for Amiga Dos 2.0x we use Open/Close/Flush instead of fopen/fclose
  29.  */
  30. #ifdef AMIGA
  31. extern int dos2;                    /* this is in amiga.c */
  32. # ifdef SASC
  33. #  include <proto/dos.h>
  34. # endif
  35. #endif
  36.  
  37. /*
  38.  * We use this flag to avoid writing :win to commands to the script file
  39.  * during startup.
  40.  */
  41. static int script_started = FALSE;
  42.  
  43. /*
  44.  * startscript(): open automatic script file
  45.  */
  46.     void
  47. startscript()
  48. {
  49.     int        n = 0;
  50.     char    buf[25];
  51.  
  52.     script_started = TRUE;
  53. #if AMIGA
  54. /*
  55.  * With Amiga DOS 2.0 the system may lockup with the sequence: write to .vim
  56.  * file, close it, delete it, create a new .vim file and write to it.
  57.  * The Delay seems to solve this problem, maybe because DOS gets a chance to
  58.  * finish the close and delete of the old .vim file.
  59.  */
  60.     if (stopscript() && dos2)
  61.         Delay(2L);        /* This should fix the lockup bug */
  62. #else
  63.     stopscript();        /* stop any old script */
  64. #endif
  65.     if (p_uc == 0)    /* no auto script wanted */
  66.         return;
  67.     if (Changed)
  68.         emsg("Warning: buffer already changed, auto script file will be incomplete");
  69.     scriptname = makescriptname();
  70.     if (scriptname)
  71.     {
  72.         while (
  73. #ifdef AMIGA
  74.             dos2 ? ((autoscriptfd = (FILE *)Open((UBYTE *)scriptname, (long)MODE_OLDFILE)) != NULL) :
  75. #endif
  76.             ((autoscriptfd = fopen(scriptname,
  77. #ifdef MSDOS
  78.                                                 "rb"
  79. #else
  80.                                                 "r"
  81. #endif
  82.                                                     )) != 0))
  83.                             /* file already exists */
  84.         {
  85. #ifdef AMIGA
  86.             if (dos2)
  87.                 Close((BPTR)autoscriptfd);
  88.             else
  89. #endif
  90.                 fclose(autoscriptfd);
  91.             autoscriptfd = NULL;
  92.             if (n == 0)                /* first time; give error message */
  93.                 emsg(".vim file exists: an edit of this file has not been finished");
  94.             n = strlen(scriptname);
  95.             /*
  96.              * If we are not able to find a name with the last character changed
  97.              * we probably have a device with shorter file names (e.g. MSDOS
  98.              * compatible). We should try with another change.
  99.              */
  100.             if (n == 0 || scriptname[n-1] == 'a')
  101.             {
  102.                 free(scriptname);
  103.                 return;
  104.             }
  105.             --scriptname[n-1];                /* change last char of the name */
  106.         }
  107. #ifdef AMIGA
  108.         if (dos2)
  109.             autoscriptfd = (FILE *)Open((UBYTE *)scriptname, (long)MODE_NEWFILE);        /* errors are ignored */
  110.         else
  111. #endif
  112.             autoscriptfd = fopen(scriptname,
  113. #ifdef MSDOS
  114.                                                 "wb"
  115. #else
  116.                                                 "w"
  117. #endif
  118.                                                     );        /* errors are ignored */
  119.         script_winsize();            /* always start with a :win command */
  120.         if (Curpos.lnum > 1 || Curpos.col > 0)
  121.         {
  122.             sprintf(buf, "%ldG0%dl", (long)Curpos.lnum, (int)Curpos.col);
  123.             Supdatescript(buf);
  124.         }
  125.  
  126.     }
  127. }
  128.  
  129.     int
  130. stopscript()
  131. {
  132.     if (!autoscriptfd)
  133.         return FALSE;        /* nothing to stop */
  134.  
  135. #ifdef AMIGA
  136.     if (dos2)
  137.         Close((BPTR)autoscriptfd);
  138.     else
  139. #endif
  140.         fclose(autoscriptfd);
  141.     remove(scriptname);        /* delete the file */
  142.     autoscriptfd = NULL;
  143.     free(scriptname);
  144.     return TRUE;
  145. }
  146.  
  147. /*
  148.  * open new script file
  149.  * return 0 on success, 1 on error
  150.  */
  151.     int
  152. openscript(name)
  153.     char *name;
  154. {
  155.     int oldcurscript;
  156.  
  157.     if (curscript + 1 == NSCRIPT)
  158.     {
  159.         emsg(e_nesting);
  160.         return 1;
  161.     }
  162.     else
  163.     {
  164.         if (scriptin[curscript] != NULL)    /* already reading script */
  165.             ++curscript;
  166.         if ((scriptin[curscript] = fopen((char *)name,
  167. #ifdef MSDOS
  168.                                                     "rb"
  169. #else
  170.                                                     "r"
  171. #endif
  172.                                                         )) == NULL)
  173.         {
  174.             emsg(e_notopen);
  175.             if (curscript)
  176.                 --curscript;
  177.             return 1;
  178.         }
  179.         /*
  180.          * With command ":g/pat/so! file" we have to execute the
  181.          * commands from the file now.
  182.          */
  183.         if (global_busy)
  184.         {
  185.             State = NORMAL;
  186.             oldcurscript = curscript;
  187.             do
  188.             {
  189.                 normal();
  190.                 vpeekc();            /* check for end of file */
  191.             }
  192.             while (scriptin[oldcurscript]);
  193.             State = CMDLINE;
  194.         }
  195.     }
  196.     return 0;
  197. }
  198.  
  199. /*
  200.  * updatescipt() is called when a character has to be written into the script file
  201.  * or when we have waited some time for a character (c == 0)
  202.  */
  203.     void
  204. updatescript(c)
  205.     int c;
  206. {
  207.     static int count = 0;
  208.  
  209.     if (c && scriptout)
  210.         putc(c, scriptout);
  211.     if (autoscriptfd == NULL || (c == 0 && count == 0))        /* nothing to do */
  212.         return;
  213.     if (c)
  214.     {
  215. #ifdef AMIGA
  216.         if (dos2)
  217.             FPutC((BPTR)autoscriptfd, (unsigned long)c);
  218.         else
  219. #endif
  220.             putc(c, autoscriptfd);
  221.         ++count;
  222.     }
  223.     if ((c == 0 || count >= p_uc) && Updated)
  224.     {
  225.         /*
  226.          * Before DOS 2.0x we have to close and open the file in order to really
  227.          * get the characters in the file to disk!
  228.          * With DOS 2.0x Flush() can be used for that
  229.          */
  230. #ifdef AMIGA
  231.         if (dos2)
  232.             Flush((BPTR)autoscriptfd);
  233.         else
  234. #endif
  235.         {
  236.             fclose(autoscriptfd);
  237.             autoscriptfd = fopen(scriptname,
  238. #ifdef MSDOS
  239.                                                 "ab"
  240. #else
  241.                                                 "a"
  242. #endif
  243.                                                      );
  244.         }
  245.         count = 0;
  246.         Updated = 0;
  247.     }
  248. }
  249.  
  250.     static void
  251. Supdatescript(str)
  252.     char *str;
  253. {
  254.     while (*str)
  255.         updatescript(*str++);
  256. }
  257.  
  258. /*
  259.  * try to open the ".vim" file for recovery
  260.  * if recoverymode is 1: start recovery, set recoverymode to 2
  261.  * if recoverymode is 2: stop recovery mode
  262.  */
  263.     void
  264. openrecover()
  265. {
  266.     char *fname;
  267.     struct stat efile, rfile;
  268.  
  269.     if (recoverymode == 2)        /* end of recovery */
  270.     {
  271.         if (got_int)
  272.         {
  273.             emsg("Recovery Interrupted");
  274.                 /* somehow the cursor ends up in the wrong place (why?) */
  275.             setcursor();
  276.             flushbuf();
  277.         }
  278.         else
  279.             msg("Recovery completed");
  280.         recoverymode = 0;
  281.     }
  282.     else
  283.     {
  284.         fname = makescriptname();
  285.         if (fname)
  286.         {
  287.             recoverymode = 2;
  288.             if (Filename != NULL &&
  289.                     stat(Filename, &efile) != -1 &&
  290.                     stat(fname, &rfile) != -1 &&
  291.                     efile.st_mtime > rfile.st_mtime)
  292.                 emsg(".vim file is older; file not recovered");
  293.             else
  294.             {
  295.                 if (openscript(fname))
  296.                     emsg("Cannot open .vim file; file not recovered");
  297.             }
  298.             free(fname);
  299.         }
  300.     }
  301. }
  302.  
  303. /*
  304.  * make script name out of the filename
  305.  */
  306.     static char *
  307. makescriptname()
  308. {
  309.     char *r, *s, *fname;
  310.  
  311.     r = modname(Filename, ".vim");
  312.     if (*p_dir == 0 || r == NULL)
  313.         return r;
  314.  
  315.     for (fname = s = r; *s; ++s)        /* skip path */
  316.     {
  317. #ifdef UNIX
  318.         if (*s == '/')        /* UNIX has ':' inside file names */
  319. #else
  320.         if (*s == ':' || *s == PATHSEP)
  321. #endif
  322.             fname = s + 1;
  323.     }
  324.  
  325.     s = alloc((unsigned)(strlen(p_dir) + strlen(fname) + 1));
  326.     if (s != NULL)
  327.     {
  328.         strcpy(s, p_dir);
  329.         strcat(s, fname);
  330.     }
  331.     free(r);
  332.     return s;
  333. }
  334.  
  335. #ifndef MSDOS        /* MSDOS has only one extention, see msdos.c */
  336. /*
  337.  * add extention to filename - change path/fo.o.h to path/fo.o.h.ext
  338.  *    Space for the new name is allocated.
  339.  */
  340.     char *
  341. modname(fname, ext)
  342.     char *fname, *ext;
  343. {
  344.     register char    *retval;
  345.     register char   *s;
  346.     register char   *ptr;
  347.     register int    fnamelen, extlen;
  348.              char    currentdir[512];
  349.  
  350.     extlen = strlen(ext);
  351.     /*
  352.      * if there is no filename we must get the name of the current directory
  353.      * (we need the full path in case :cd is used)
  354.      */
  355.     if (fname == NULL || *fname == NUL)    
  356.     {
  357.         (void)dirname(currentdir, 511);
  358.         strcat(currentdir, PATHSEPSTR);
  359.         fnamelen = strlen(currentdir);
  360.     }
  361.     else
  362.         fnamelen = strlen(fname);
  363.     retval = alloc((unsigned) (fnamelen + extlen + 1));
  364.     if (retval != NULL)
  365.     {
  366.         if (fname == NULL || *fname == NUL)
  367.             strcpy(retval, currentdir);
  368.         else
  369.             strcpy(retval, fname);
  370.         for (ptr = s = retval; *s; s++)
  371.         {
  372. #ifdef UNIX
  373.             if (*s == '/')        /* UNIX has ':' inside file names */
  374. #else
  375.             if (*s == ':' || *s == PATHSEP)
  376. #endif
  377.                 ptr = s + 1;
  378.         }
  379.         if (s - ptr > 30 - extlen)            /* if filename too long, truncate it */
  380.             s = ptr + 30 - extlen;
  381.         /*
  382.          * Replace all '.' by '_' in filename. This avoids problems with
  383.          * MSDOS-like filesystems.
  384.          */
  385.         for ( ; *ptr; ++ptr)
  386.             if (*ptr == '.')
  387.                 *ptr = '_';
  388.         strcpy(s, ext);
  389.         if (fname != NULL && strcmp(fname, retval) == 0)
  390.             *s = '_';                /* filename already ended in ext */
  391.     }
  392.     return retval;
  393. }
  394. #endif    /* MSDOS */
  395.  
  396. /*
  397.  * the new window size must be used in scripts;
  398.  * write a ":winsize width height" command to the (auto)script
  399.  * Postpone this action if not in NORMAL State, otherwise we may insert the
  400.  * command halfway another command.
  401.  */
  402. int script_winsize_postponed = FALSE;
  403.  
  404.     void
  405. script_winsize()
  406. {
  407.     char            buf[25];
  408.  
  409.     if (!script_started || State != NORMAL)        /* postpone action */
  410.     {
  411.         script_winsize_postponed = TRUE;
  412.         return;
  413.     }
  414.  
  415.     sprintf(buf, ":win %d %d\r", (int)Columns, (int)Rows);
  416.     Supdatescript(buf);
  417.     script_winsize_postponed = FALSE;
  418. }
  419.  
  420. /*
  421.  * This function is called after each "State = NORMAL"
  422.  */
  423.     void
  424. script_winsize_pp()
  425. {
  426.     if (script_winsize_postponed)
  427.         script_winsize();
  428. }
  429.